//
//  YXImageCache.m
//  YXImageBrowserDemo
//
//  Created by guo peng huang on 2021/5/18.
//

#import "YXImageCache.h"
#import "YXImageCache+Internal.h"
#import "YXUtilities.h"
#import <objc/runtime.h>

@implementation NSObject (YXImageCache)
static void *YXImageCacheKey = &YXImageCacheKey;

- (void)setYx_imageCache:(YXImageCache * _Nonnull)yx_imageCache {
    objc_setAssociatedObject(self, YXImageCacheKey, yx_imageCache, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (YXImageCache *)yx_imageCache {
    YXImageCache *cache = objc_getAssociatedObject(self, YXImageCacheKey);
    if (!cache) {
        cache = [YXImageCache new];
        self.yx_imageCache = cache;
    }
    return cache;
}
@end

@interface YXImageCachePack : NSObject
@property (nonatomic, strong) UIImage *originImage;
@property (nonatomic, strong) UIImage *compressedImage;
@end
@implementation YXImageCachePack
@end

@implementation YXImageCache {
    NSCache<NSString *, YXImageCachePack *> *_imageCache;
    NSMutableDictionary<NSString *, YXImageCachePack *> *_residentCache;
}

#pragma mark - life cycle

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
}

- (instancetype)init {
    self = [super init];
    if (self) {
        _imageCache = [NSCache new];
        _imageCache.countLimit = _yx_imageCacheCountLimit = YXLowMemory() ? 6 : 12;
        _residentCache = [NSMutableDictionary dictionary];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
    }
    return self;
}

#pragma mark - event

- (void)didReceiveMemoryWarning:(NSNotification *)notification {
    [_imageCache removeAllObjects];
    [_residentCache removeAllObjects];
}

#pragma mark - public

- (void)yx_setImage:(UIImage *)image type:(YXImageCacheType)type forKey:(NSString *)key resident:(BOOL)resident {
    YXImageCachePack *pack = [_imageCache objectForKey:key];
    if (!pack) {
        pack = [YXImageCachePack new];
        [_imageCache setObject:pack forKey:key];
    }
    switch (type) {
        case YXImageCacheTypeOrigin:
            pack.originImage = image;
            break;
        case YXImageCacheTypeCompressed:
            pack.compressedImage = image;
            break;
    }
    [_residentCache setObject:pack forKey:key];
}

- (UIImage *)yx_imageForKey:(NSString *)key type:(YXImageCacheType)type {
    YXImageCachePack *pack = [_imageCache objectForKey:key] ?: [_residentCache objectForKey:key];
    switch (type) {
        case YXImageCacheTypeOrigin: return pack.originImage;
        case YXImageCacheTypeCompressed: return pack.compressedImage;
        default: return nil;
    }
}

- (void)yx_removeForKey:(NSString *)key {
    [_imageCache removeObjectForKey:key];
    [_residentCache removeObjectForKey:key];
}

- (void)yx_removeResidentForKey:(NSString *)key {
    [_residentCache removeObjectForKey:key];
}

- (void)setYx_imageCacheCountLimit:(NSUInteger)yx_imageCacheCountLimit {
    _yx_imageCacheCountLimit = yx_imageCacheCountLimit;
    _imageCache.countLimit = yx_imageCacheCountLimit;
}

@end
